import { ElementRef, EventEmitter, Injectable, Injector, OnDestroy } from '@angular/core';
import { Edge, EdgeView, Graph, Node, Shape } from '@antv/x6';
import { Options } from '@antv/x6/lib/graph/options';
import { uuid } from '@antv/x6/lib/util/string/uuid';
import { cloneDeep } from 'lodash';
import { BehaviorSubject } from 'rxjs';
import { EdgeData, NodeData } from '../cell-set/type';
import { WfEdge } from '../component';
import { SHAPE_TYPE } from '../shared/enum';
import { getSourceNodeByEdge } from './util';

@Injectable({
  providedIn: 'root'
})
export class GraphService implements OnDestroy {


  btnJson$ = new EventEmitter<boolean>();
  minMapBtn$ = new EventEmitter<boolean>();
  graph$ = new BehaviorSubject<Graph | undefined>(undefined);
  addPort$ = new EventEmitter<void>();

  private graph!: Graph;

  private graphConfig: Partial<Options.Manual> = {
    container: undefined,
    autoResize: true,
    grid: { // 网格
      size: 15,      // 网格大小 10px
      visible: true, // 绘制网格，默认绘制 dot 类型网格
      type: 'doubleMesh', // 'dot' | 'fixedDot' | 'mesh'
      args: [
        {
          color: '#aaaaaa',
          thickness: 1,
        },
        {
          color: 'rgba(190,190,190)',
          thickness: 2,
          factor: 4,
        }]
    },
    keyboard: { // 键盘快捷键，默认禁用。创建画布时通过以下配置启用。
      enabled: true,
      // global: true
    },
    history: true,
    scroller: {
      enabled: true,
      pageVisible: true,
      pageBreak: true,
      pannable: true,
      // modifiers: ['shift']
    },
    mousewheel: { // 缩放
      enabled: true,
      minScale: 0.5,
      maxScale: 2,
      modifiers: ['ctrl'],
      global: true
    },
    minimap: { //小地图
      enabled: true,
      container: undefined,
    },
    resizing: { // 缩放节点，默认禁用。开启后可以对节点进行缩放。
      enabled: false,
    },
    selecting: {
      enabled: true,
      multiple: false,
      showEdgeSelectionBox: true,
      showNodeSelectionBox: true,
      movable: true,
      following: true,
    },
    connecting: {
      snap: true,
      allowBlank: false,
      allowEdge: false,
      allowLoop: false,
      allowMulti: false,
      highlight: true,
      allowNode: true,
      allowPort: true,
      router: {
        name: 'manhattan',
        args: {
          step: 15,
          startDirections: ['bottom'],
          endDirections: ['top'],
        },
      },
      validateMagnet({ magnet, cell }) {
        let count = 0;
        const connectionCount = magnet.getAttribute('connection-count');
        const max = connectionCount ? parseInt(connectionCount, 10) : Number.MAX_SAFE_INTEGER;

        const graph = this;

        const outgoingEdges = graph.getOutgoingEdges(cell);
        if (outgoingEdges) {
          outgoingEdges.forEach((edge: Edge) => {
            const edgeView = graph.findViewByCell(edge) as EdgeView;
            if (edgeView.sourceMagnet === magnet) {
              count += 1;
            }
          });
        }
        return count < max;
      },
      createEdge({ sourceCell }) {
        const data = sourceCell.getData();
        if (data && (data.type === 'start' || data.type === 'end')) {
          return new Shape.Edge();
        }
        return new WfEdge();
      },
      validateConnection({
        targetMagnet,
        targetCell
      }) {
        if (targetMagnet) {
          const portType = targetMagnet.getAttribute('port-group');
          if (portType === 'out') {
            return false;
          }
          if (portType === 'start') {
            return false;
          }
          return true;
        }

        if (targetCell && targetCell.isNode) {
          const data = targetCell.getData();
          if (data && data.type === 'start') {
            return false;
          }
        }
        return true;
      },
    },
  };


  constructor() {
  }
  ngOnDestroy(): void {
    if (this.graph$) {
      this.graph$.unsubscribe();
    }
  }

  /**
   * @description 设置容器节点和小地图节点，并创建graph
  */
  setAnchor(container: ElementRef, minimap: ElementRef) {
    this.graphConfig.container = container.nativeElement;
    (this.graphConfig.minimap as Partial<Graph.MiniMapManager.Options>).container = minimap.nativeElement;

    this.createGraph();
  }

  /**
   * @description 创建graph
  */
  private createGraph() {
    this.graph = new Graph(this.graphConfig);
    this.graph$.next(this.graph);

    this.init();
    this.listenEvent();
  }

  /**
   * @description 初始化三个节点开始结束
  */
  private init() {

    const start = this.graph.addNode({
      x: 600,
      y: 10,
      width: 80,
      height: 40,
      shape: 'rect',
      data: {
        type: 'start'
      },
      attrs: {
        body: {
          fill: '#3F4652',
        },
        label: {
          text: '开始',
          fill: 'white',
        },
      },
      ports: {
        groups: {
          start: {
            id: 'start',
            position: 'bottom',
            label: {
              position: 'right',
            },
            attrs: {
              circle: {
                r: 6,
                magnet: true,
                connectionCount: 1, // 自定义属性，控制连接桩可连接多少条边
                stroke: '#073190',
                strokeWidth: 2,
                fill: '#fff',
              },
            },
          }
        },
        items: [
          { id: 'start', group: 'start' }]
      }
    });

    const initNode = this.graph.addNode({
      shape: SHAPE_TYPE.TEXT,
      x: 560,
      y: 150,
      data: {
        btnList: [
          { value: '返回', sort: 1, id: uuid(), allot: false, from: 'btn' },
          { value: '继续', sort: 2, id: uuid(), allot: false, from: 'btn' },
        ]
      },
      ports: [
        {
          group: 'out',
          attrs: {
            text: { text: '继续' },
          },
        },
      ]
    });

    const end = this.graph.addNode({
      x: 600,
      y: 350,
      width: 80,
      height: 40,
      shape: 'rect',
      data: {
        type: 'end'
      },
      attrs: {
        body: {
          fill: '#3F4652',
        },
        label: {
          text: '结束',
          fill: 'white',
        },
      },
    });

    this.graph.addEdge({
      shape: 'edge',
      source: { cell: start, port: 'start' },
      target: initNode,
    });

    this.graph.addEdge({
      shape: 'wf-edge',
      source: { cell: initNode, port: initNode.getPortAt(0).id },
      target: end,
    });

    this.graph.center();
  }

  /**
   * @description 节点，边事件的监听
  */
  private listenEvent() {
    this.graph.on('node:dblclick', ({ node, e }) => {
      if (node.shape !== 'rect') {
        const p = this.graph.clientToGraph(e.clientX, e.clientY);
        node.addTools([
          {
            name: 'editableCell',
            args: {
              x: p.x,
              y: p.y,
            },
          },
        ]);
      }
    });

    this.graph.on('node:contextmenu', ({ node, e }) => {
      console.log('cell:contextmenu');
      if (node.shape !== 'rect') {
        const that = this;
        const p = this.graph.clientToGraph(e.clientX, e.clientY);
        node.addTools([
          {
            name: 'nodeContextmenu',
            args: {
              x: p.x,
              y: p.y,
              onHide() {
                this.cell.removeTool('nodeContextmenu');
              },
              onClick(event: Event) {
                const type = (event!.target! as HTMLElement).getAttribute('custom-type');
                if (type === '1') {
                  node.remove();
                }

                if (type === '2') {
                  node.addPort({
                    group: 'out',
                  });
                  that.addPort$.emit();
                }
              }
            },
          },
        ]);
      }
    });

    this.graph.on('edge:contextmenu', ({ edge, e }) => {

      const p = this.graph.clientToGraph(e.clientX, e.clientY);
      edge.addTools([
        {
          name: 'edgeContextmenu',
          args: {
            x: p.x,
            y: p.y,
            onHide() {
              this.cell.removeTool('edgeContextmenu');
            },
            onClick(event: Event) {
              const type = (event!.target! as HTMLElement).getAttribute('custom-type');
              if (type === '1') {
                if (edge.shape === 'wf-edge') {
                  const sourceNode = getSourceNodeByEdge(edge, this.graph);
                  const nodeData = cloneDeep(sourceNode.getData<NodeData>());
                  const edgeData = cloneDeep(edge.getData<EdgeData>());
                  if (edgeData.btnTrigger.length > 0) {
                    const tempList = edgeData.btnTrigger.filter(i => i.from === 'btn');
                    tempList.forEach(btn => {
                      const data = nodeData.btnList.find(i => i.id === btn.id);
                      if (data) {
                        data.allot = false;
                      }
                    });
                    sourceNode.updateData<NodeData>(nodeData);
                  }
                }
                edge.remove();
              }
            }
          },
        },
      ]);
    });

    this.graph.on('edge:change:data', ({ edge }) => {
      console.log('edge:change:data', edge);

      const data = edge.getData();
      if (data && data.btnTrigger.length > 0) {
        edge.setLabels('👆🎙️');
        return;
      }
      if (data && (data.btnTrigger.length === 0) && (data.voiceTrigger.length > 0)) {
        edge.setLabels('🎙️');
        return;
      }
      edge.setLabels('❓');
    });


    // this.graph.on('edge:mouseenter', ({ edge }) => {
    //   edge.addTools(['vertices', 'segments']);
    // });

    // this.graph.on('edge:mouseleave', ({ edge }) => {
    //   edge.removeTool('vertices');
    //   edge.removeTool('segments');
    // });
  }

}
